package com.csaba.connector.otp;

import java.io.StringReader;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.httpclient.NameValuePair;

import com.csaba.connector.ServiceException;
import com.csaba.connector.model.Account;
import com.csaba.connector.model.Customer;
import com.csaba.connector.model.HistoryItem;
import com.csaba.connector.model.Session;
import com.csaba.connector.otp.model.OTPBank;
import com.csaba.connector.otp.model.OTPRequestFactory;
import com.csaba.connector.otp.model.OTPSession;
import com.csaba.connector.otp.parser.LoginParser;
import com.csaba.connector.otp.parser.OTPCodes;
import com.csaba.connector.service.AbstractLoginService;
import com.csaba.connector.service.AccountHistoryService;
import com.csaba.connector.service.AccountService;
import com.csaba.connector.service.LoginService;
import com.csaba.connector.service.LogoutService;
import com.csaba.util.LoggerHelper;

public class OTPLoginService extends AbstractLoginService
{
	private final static Logger logger = LoggerHelper.getDefaultLogger();

	public final static String RP_ACCOUNT1 = "account1";
	public final static String RP_ACCOUNT2 = "account2";
	public final static String RP_ACCOUNT3 = "account3";

	@Override
	public void execute( final Session nullSession ) throws ServiceException
	{
		if ( customer == null )
			throw new ServiceException("Login service is not correctly initialized.");
		if ( nullSession != null )
			throw new ServiceException("Session is already initialized. Cannot login again in the same session.");

		this.session = new OTPSession();

		final String userId = customer.getLoginId();
		final String accountNr1 = (String) customer.getRemoteProperty(RP_ACCOUNT1);
		final String accountNr2 = (String) customer.getRemoteProperty(RP_ACCOUNT2);
		final String accountNr3 = (String) customer.getRemoteProperty(RP_ACCOUNT3);

		final OTPSession otp = (OTPSession) this.session;
		final NameValuePair[] loginData = new NameValuePair[] {// 
				new NameValuePair("azonosito", userId),
				new NameValuePair("jelszo", customer.getPassword()), // 
				new NameValuePair("muvelet", "login"),
				new NameValuePair("cacheHasznalat", "on"),
				new NameValuePair("honlapAzonosito", "Default.User"),
				new NameValuePair("tranzakcionkentiAzonositas", "off"),
				new NameValuePair("x", String.valueOf((int) ( Math.random() * 30 ))), //mouse cursor coordinates on the "login" button
				new NameValuePair("y", String.valueOf((int) ( Math.random() * 30 ))), //fill with random values.
				new NameValuePair("szamlaSzam.kulso[0]", accountNr1),
				new NameValuePair("szamlaSzam.kulso[1]", accountNr2),// 
				new NameValuePair("szamlaSzam.kulso[2]", accountNr3), };

		final String result = otp.doPost(OTPRequestFactory.HOMEBANK_REQUEST_URL_BASE + OTPRequestFactory.REQUEST_LOGIN,
				loginData);

		otp.debugFile("login", result);

		//decide on error 
		if ( LoginParser.isErrorOccured(result) )
		{
			logger.fine("Error during login... Parsing messaging.");
			String message = null;
			try
			{
				message = LoginParser.parseLoginError(new StringReader(result));
			}
			catch ( final Exception ex )
			{
				throw new ServiceException("Error during processing login result (error message).", ex);
			}

			throw new ServiceException("Error occured during logging in.", message);
		}
		else
		{
			logger.fine("Login was succesful.");

			//fix customer properties
			customer.setId(userId);
			customer.setBank(OTPBank.getInstance());
			customer.setName("<OTP Customer - " + userId + ">"); //TODO find out user name

			//fix session properties
			session.setCustomer(customer);

			//store account balance request in the session for further processing.
			this.session.setRemoteProperty(OTPCodes.CACHE_ACCOUNT_LIST_REQUEST, result);

			//FIXME parse login result if it is succesful. Maybe account list has to be invoked, as that contains user name, and last login information.
		}
	}

	public static void main( final String[] args ) throws ServiceException
	{
		LoggerHelper.initLogger(Level.FINE);
		//Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.FINE);

		final LoginService login = new OTPLoginService();
		final Customer customer = new Customer();
		customer.setLoginId(args[0]);
		customer.setPassword(args[1]);
		//		customer.setRemoteProperty("szamlaSzam.kulso[0]", args[2]);
		//		customer.setRemoteProperty("szamlaSzam.kulso[1]", args[3]);
		//		customer.setRemoteProperty("szamlaSzam.kulso[2]", "");
		login.setCustomer(customer);
		try
		{
			login.execute(null);
		}
		catch ( final ServiceException e )
		{
			logger.log(Level.SEVERE, "Native error:" + e.getNativeMessage(), e);
			throw e;
		}
		final Session session = login.getSession();

		///homebank/do/profile: what is it for? - this is for testing AJAX enabled browser only. Nothing useful is returned.

		try
		{
			final AccountService account = new OTPAccountService();
			account.execute(session);
			final Account[] accounts = account.getAccounts();
			if ( accounts != null )
			{
				for ( final Account acc : accounts )
				{
					logger.info("Account received: " + acc);
				}
			}
			else
			{
				logger.warning("No account is available.");
			}

			final AccountHistoryService history = new OTPAccountHistoryService();
			history.setAccount(accounts[0]);

			final Calendar to = Calendar.getInstance();
			final Calendar from = Calendar.getInstance();
			//from.roll(Calendar.DATE, false); //get last day transactions
			from.roll(Calendar.MONTH, false); //get last month transactions
			history.setDateRange(from.getTime(), to.getTime());

			history.execute(session);

			final HistoryItem[] items = history.getHistory();

			if ( items != null && items.length > 0 )
			{
				for ( int i = 0; i < items.length; i++ )
				{
					logger.fine("items[" + i + "]=" + items[i]);
				}
			}
			else
			{
				logger.fine("No transactions found for account: " + accounts[0]);
			}
		}
		catch ( final Exception e )
		{
			e.printStackTrace();
		}

		final LogoutService logout = new OTPLogoutService();
		logout.execute(session);

	}
}
